home *** CD-ROM | disk | FTP | other *** search
- // vim: ts=2 sw=2 expandtab cindent
- //
- // BEGIN FLOCK GPL
- //
- // Copyright Flock Inc. 2005-2007
- // http://flock.com
- //
- // This file may be used under the terms of of the
- // GNU General Public License Version 2 or later (the "GPL"),
- // http://www.gnu.org/licenses/gpl.html
- //
- // Software distributed under the License is distributed on an "AS IS" basis,
- // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- // for the specific language governing rights and limitations under the
- // License.
- //
- // END FLOCK GPL
- //
-
- const Cc = Components.classes;
- const Ci = Components.interfaces;
- const Cr = Components.results;
-
- const CLASS_ID = Components.ID("{2fd8e108-f21b-11db-8314-0800200c9a66}");
- const CONTRACT_ID = "@flock.com/profiler;1";
- const CATEGORY_COMPONENT_NAME = "Flock Profiler Component";
-
- const GRAPH_HOST = "dippy.hq.flock.com";
- const CREATEGRAPH_URL = "http://%host%/ffgraphs.xml";
- const OBSERVATION_URL = "http://%host%/ffgraphs/%graphname%/ffmeasurements.xml";
-
- const PREF_PROFILER = "flock.profiler.enabled";
- const PREF_REPORTING = "flock.profiler.reporting.enabled";
-
- const EVENT_FLOCKDATAREADY = "flock-data-ready";
- const EVENT_XPCOMSHUTDOWN = "xpcom-shutdown";
-
- var gGraphNames = [];
-
- var gCompTK;
- function getCompTK() {
- if (!gCompTK) {
- gCompTK = Cc["@flock.com/singleton;1"]
- .getService(Ci.flockISingleton)
- .getSingleton("chrome://browser/content/flock/services/common/load-compTK.js")
- .wrappedJSObject;
- }
- return gCompTK;
- }
-
-
- // ===============================================
- // ========== BEGIN flockProfiler class ==========
- // ===============================================
-
- function flockProfiler()
- {
- // Use a logger to spit out data to the console
- this._logger = Cc["@flock.com/logger;1"].createInstance(Ci.flockILogger);
- this._logger.init("profiler");
-
- // The System Info service will be used to get some performance data
- this._sysinfo = Cc["@flock.com/sysinfo;1"].getService(Ci.flockISystemInfo);
- var buildInfo = this._sysinfo.getBuildInfo().split(",");
- this._platform = buildInfo[0];
- this._firstRun = (buildInfo[1] == "1");
- this._startTime = (new Date()).getTime();
- //this._startTime = this._sysinfo.getStartTime();
- var sysinfoTime = this._sysinfo.getStartTime();
- this._logger.debug("start time reported by sysinfo:"+sysinfoTime);
- this._logger.info("construction time: "+this._startTime);
-
- // Register to observe application initialization and shutdown events
- this._obs = Cc["@mozilla.org/observer-service;1"]
- .getService(Ci.nsIObserverService);
- this.mInitialized = false;
- this._obs.addObserver(this, EVENT_FLOCKDATAREADY, false); // calls _init()
- this._obs.addObserver(this, EVENT_XPCOMSHUTDOWN, false);
-
- // This will be used to store open profiling events
- this._eventQueue = [];
-
- // These will be overridden in _init()
- this._profilingEnabled = false;
- this._reportingEnabled = false;
-
- // Use Component Toolkit to implement basic interfaces
- this._ctk = {
- interfaces: [
- "nsISupports",
- "nsIClassInfo",
- "nsISupportsCString",
- "nsIObserver",
- "flockIProfiler"
- ],
- shortName: "profiler",
- fullName: "Flock Profiler",
- CID: CLASS_ID,
- contractID: CONTRACT_ID
- };
- }
-
-
- // BEGIN nsIObserver
- flockProfiler.prototype.observe =
- function flockProfiler_observe(aSubject, aTopic, aData)
- {
- switch (aTopic) {
-
- case EVENT_FLOCKDATAREADY:
- {
- this._obs.removeObserver(this, EVENT_FLOCKDATAREADY);
- this._init();
- }; break;
-
- case EVENT_XPCOMSHUTDOWN:
- {
- this._obs.removeObserver(this, EVENT_XPCOMSHUTDOWN);
-
- // Don't accept any more profiling calls or reporting after shutdown
- this._profilingEnabled = false;
- this._reportingEnabled = false;
-
- // Flush the event queue
- this._eventQueue = [];
- }; break;
-
- }
- }
- // END nsIObserver
-
-
- // BEGIN flockIProfiler
- flockProfiler.prototype.profile =
- function flockProfiler_profile(aEventName, aMessage)
- {
- this._init();
- if (!this._profilingEnabled) return;
- var inst = this;
- var pEvent = {
- seq: inst._getProfileSeq(),
- name: aEventName,
- clock: inst._getTimeSinceStart(),
- msg: aMessage,
- ready: true
- };
- pEvent.cpu = this._sysinfo.getCPU();
- pEvent.mem = this._sysinfo.getMem();
- this._eventQueue.push(pEvent);
- this._logEvent(pEvent);
- }
-
- flockProfiler.prototype.profileEventStart =
- function flockProfiler_profileEventStart(aEventName)
- {
- this._init();
- if (!this._profilingEnabled) return 0;
- var inst = this;
- var pEvent = {
- seq: inst._getProfileSeq(),
- name: aEventName,
- clock: inst._getTimeSinceStart()
- };
- //pEvent.cpu = this._sysinfo.getCPU();
- //pEvent.mem = this._sysinfo.getMem();
- this._eventQueue.push(pEvent);
- //this._logEvent(pEvent);
- return pEvent.seq;
- }
-
- flockProfiler.prototype.profileEventEnd =
- function flockProfiler_profileEventEnd(aEventID, aMessage)
- {
- if (!this._profilingEnabled) return;
- // Find the event start
- var pEvent = null;
- for (var i = this._eventQueue.length - 1; i >= 0; i--) {
- if (this._eventQueue[i].seq == aEventID) {
- pEvent = this._eventQueue[i];
- break;
- }
- }
- if (!pEvent) return;
- pEvent.duration = this._getTimeSinceStart() - pEvent.clock;
- pEvent.cpu = this._sysinfo.getCPU();
- pEvent.mem = this._sysinfo.getMem();
- pEvent.msg = aMessage;
- pEvent.ready = true;
- this._logEvent(pEvent);
- }
- // END flockIProfiler
-
-
- flockProfiler.prototype._init =
- function flockProfiler__init()
- {
- if (this.mInitialized) return;
-
- // Check prefs to see if we should be enabled
- var prefSvc = Cc["@mozilla.org/preferences-service;1"]
- .getService(Ci.nsIPrefBranch);
- this._profilingEnabled = ( prefSvc.getPrefType(PREF_PROFILER) &&
- prefSvc.getBoolPref(PREF_PROFILER) );
- this._reportingEnabled = ( prefSvc.getPrefType(PREF_REPORTING) &&
- prefSvc.getBoolPref(PREF_REPORTING) );
-
- // Kick off a timer for processing the event queue
- if (this._profilingEnabled && this._reportingEnabled) {
- var inst = this;
- var timerCB = { notify: function (aTimer) { inst._processEventQueue(); } };
- var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
- timer.initWithCallback(timerCB, 10 * 1000, Ci.nsITimer.TYPE_ONE_SHOT);
- }
-
- this.mInitialized = true;
- }
-
- flockProfiler.prototype._getProfileSeq =
- function flockProfiler__getProfileSeq()
- {
- return this._eventQueue.length + 1;
- }
-
- flockProfiler.prototype._logEvent =
- function flockProfiler__logEvent(aEvent)
- {
- var msg = "";
- var props = ["seq","name","clock","duration","cpu","mem","msg"];
- for (var p in props) {
- if (aEvent[props[p]] == undefined) continue;
- if (msg.length > 0) msg += " ";
- msg += props[p]+":"+aEvent[props[p]];
- }
- this._logger.info(msg);
- }
-
- flockProfiler.prototype._getTimeSinceStart =
- function flockProfiler__getTimeSinceStart()
- {
- var timeNow = (new Date()).getTime();
- var timeElapsed = timeNow - this._startTime;
- //dump("CDC profiling: timeNow: "+timeNow+" timeElapsed:"+timeElapsed+"\n");
- return timeElapsed;
- }
-
- flockProfiler.prototype._ensureGraphExists =
- function flockProfiler__ensureGraphExists(aGraphName, aUnits, aListener)
- {
- if (!this._reportingEnabled) return;
- if (gGraphNames[aGraphName] != undefined) {
- aListener.onSuccess();
- } else {
- var inst = this;
- var hr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
- .createInstance(Ci.nsIXMLHttpRequest);
- hr.onreadystatechange = function (aEvent) {
- if (hr.readyState == 4) {
- gGraphNames[aGraphName] = true;
- //inst._logger.info("created graph: "+aGraphName);
- //inst._logger.info("graph creation status: "+hr.status+" "+hr.statusText);
- //inst._logger.info("response text:"+hr.responseText);
- aListener.onSuccess();
- }
- };
- var graphURL = CREATEGRAPH_URL.replace("%host%", GRAPH_HOST)
- hr.open("POST", graphURL);
- var postBody = "ffgraph[name]="+aGraphName
- + "&ffgraph[units]="+aUnits
- + "&ffgraph[password]=flock";
- //inst._logger.info("POST to URL: "+graphURL);
- //inst._logger.info("POST body: "+postBody);
- hr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
- hr.send(postBody);
- }
- }
-
- flockProfiler.prototype._submitObservations =
- function flockProfiler__submitObservations(aProfilingEvent)
- {
- if (!this._reportingEnabled) return;
- var obsTypes = ["clock","duration","cpu","mem"];
- var obsUnits = ["ms","ms","%","Mb"];
- for (var i in obsTypes) {
- var obsType = obsTypes[i];
- if (aProfilingEvent[obsType] != undefined) {
- switch (obsType) {
- case "cpu": case "mem":
- // Don't bother recording null observations
- if (aProfilingEvent[obsType] == 0) { continue; }
- }
- var graphName = aProfilingEvent.name+"%20"+obsType+"%20"+this._platform;
- if (this._firstRun) graphName += "%20FR";
- var inst = this;
- var graphCreationListener = {
- graphName: graphName,
- obsType: obsType,
- onSuccess: function () {
- if (!inst._reportingEnabled) return;
- var hr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
- .createInstance(Ci.nsIXMLHttpRequest);
- hr.onreadystatechange = function (aHTTPEvent) {
- if (hr.readyState == 4) {
- aProfilingEvent.sent = true;
- }
- };
- var obsURL = OBSERVATION_URL.replace("%host%", GRAPH_HOST)
- .replace("%graphname%", this.graphName);
- hr.open("POST", obsURL);
- var postBody = "ffmeasurement[data]="+aProfilingEvent[this.obsType]
- + "&ffmeasurement[notes]="+escape(aProfilingEvent.msg);
- //inst._logger.info("POST to URL: "+obsURL);
- //inst._logger.info("POST body: "+postBody);
- hr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
- hr.setRequestHeader("Authorization", "Basic OmZsb2Nr"); // Base64(":flock")
- hr.send(postBody);
- }
- };
- this._ensureGraphExists(graphName, obsUnits[i], graphCreationListener);
- }
- }
- }
-
- flockProfiler.prototype._processEventQueue =
- function flockProfiler__processEventQueue()
- {
- if (!this._reportingEnabled) return;
- //this._logger.info("_processEventQueue()");
- while (this._eventQueue.length && this._eventQueue[0].sent) {
- this._eventQueue.shift();
- }
- var profilingEvent = null;
- var pos = 0;
- while (!profilingEvent && (pos < this._eventQueue.length)) {
- if (this._eventQueue[pos].ready) {
- profilingEvent = this._eventQueue[pos];
- break;
- }
- pos++;
- }
- if (profilingEvent) {
- this._submitObservations(profilingEvent);
- }
- var inst = this;
- var timerCB = { notify: function (aTimer) { inst._processEventQueue(); } };
- var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
- timer.initWithCallback(timerCB, 5 * 1000, Ci.nsITimer.TYPE_ONE_SHOT);
- }
- // ========== END flockProfiler class ==========
-
-
- // ================================================
- // ========== BEGIN XPCOM Module support ==========
- // ================================================
-
- function createModule(aParams) {
- return {
- registerSelf: function (aCompMgr, aFileSpec, aLocation, aType) {
- aCompMgr.QueryInterface(Ci.nsIComponentRegistrar);
- aCompMgr.registerFactoryLocation( aParams.CID, aParams.componentName,
- aParams.contractID, aFileSpec,
- aLocation, aType );
- var catMgr = Cc["@mozilla.org/categorymanager;1"]
- .getService(Ci.nsICategoryManager);
- catMgr.addCategoryEntry( "flock-startup", aParams.componentName,
- "service,"+aParams.contractID, true, true );
- if (!aParams.categories) { aParams.categories = []; }
- for (var i = 0; i < aParams.categories.length; i++) {
- var cat = aParams.categories[i];
- catMgr.addCategoryEntry( cat.category, cat.entry,
- cat.value, true, true );
- }
- },
- getClassObject: function (aCompMgr, aCID, aIID) {
- if (!aCID.equals(aParams.CID)) { throw Cr.NS_ERROR_NO_INTERFACE; }
- if (!aIID.equals(Ci.nsIFactory)) { throw Cr.NS_ERROR_NOT_IMPLEMENTED; }
- return { // Factory
- createInstance: function (aOuter, aIID) {
- if (aOuter != null) { throw Cr.NS_ERROR_NO_AGGREGATION; }
- var comp = new aParams.componentClass();
- if (aParams.implementationFunc) { aParams.implementationFunc(comp); }
- return comp.QueryInterface(aIID);
- }
- };
- },
- canUnload: function (aCompMgr) { return true; }
- };
- }
-
- // NS Module entrypoint
- function NSGetModule(aCompMgr, aFileSpec) {
- return createModule({
- componentClass: flockProfiler,
- CID: CLASS_ID,
- contractID: CONTRACT_ID,
- componentName: CATEGORY_COMPONENT_NAME,
- implementationFunc: function (aComp) { getCompTK().addAllInterfaces(aComp); }
- });
- }
-
- // ========== END XPCOM Module support ==========
-